package kz.kstu.scantest.business.server.util;

import kz.kstu.scantest.business.common.helper.FormDataHelper;
import kz.kstu.scantest.business.entity.data.*;
import kz.kstu.scantest.business.entity.form.Form;
import kz.kstu.scantest.business.entity.form.Field;
import kz.kstu.scantest.business.entity.data.FieldNameEnum;
import kz.kstu.scantest.business.entity.data.SubjectEnum;
import kz.kstu.scantest.business.util.DateUtil;
import kz.kstu.scantest.business.util.StringUtil;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author Filipp_Stankevich
 *         created: 08.09.11 17:00
 */
public class FormDataParser {

    public static final Logger LOGGER = Logger.getLogger(FormDataParser.class);

    private final static String DEFAULT_CHARSET = "Cp1251";

    private boolean errorSaved = false;

    private final static Map<Integer, SubjectEnum> SUBJECT_VALUE_MAP = new HashMap<Integer, SubjectEnum>() {
        {
            BigInteger integer = new BigInteger(new byte[]{'5', 32});
            put(integer.intValue(), SubjectEnum.PHYSICS);
            integer = new BigInteger(new byte[]{'6', 32});
            put(integer.intValue(), SubjectEnum.CHEMISTRY);
            integer = new BigInteger(new byte[]{'7', 32});
            put(integer.intValue(), SubjectEnum.BIOLOGY);
            integer = new BigInteger(new byte[]{'8', 32});
            put(integer.intValue(), SubjectEnum.GEOGRAPHY);
            integer = new BigInteger(new byte[]{'9', 32});
            put(integer.intValue(), SubjectEnum.WORLD_HISTORY);
            integer = new BigInteger(new byte[]{'1', '0'});
            put(integer.intValue(), SubjectEnum.LITERATURE);
            integer = new BigInteger(new byte[]{'1', '1'});
            put(integer.intValue(), SubjectEnum.ENGLISH);
            integer = new BigInteger(new byte[]{'1', '2'});
            put(integer.intValue(), SubjectEnum.GERMAN);
            integer = new BigInteger(new byte[]{'1', '3'});
            put(integer.intValue(), SubjectEnum.FRENCH);
        }
    };

    private final static Map<Byte, String> KAZAKH_LETTER = new HashMap<Byte, String>() {
        {
            put((byte) 163, "Ә");
            put((byte) 170, "Ғ");
            put((byte) 141, "Қ");
            put((byte) 189, "Ң");
            put((byte) 165, "Ө");
            put((byte) 161, "Ұ");
            put((byte) 175, "Ү");
            put((byte) 142, "Һ");
            put((byte) 178, "І");
        }
    };

    private final static Map<FieldNameEnum, FieldNameEnum> SUBJECT_FIELD_MAP = new HashMap<FieldNameEnum, FieldNameEnum>() {
        {
            put(FieldNameEnum.FIFTH_SUBJECT, FieldNameEnum.FIFTH_SUBJECT_NAME);
        }
    };

    private byte[] data;
    private Form form;
    private FormData formData = new FormData();

    public FormDataParser(Form form, byte[] data) {
        this.form = form;
        this.data = data;
    }

    public FormData process() throws UnsupportedEncodingException {
        for (Map.Entry<FieldNameEnum, Field> entry : form.getFields().entrySet()) {
            processField(entry.getValue());
        }
        return formData;
    }

    private void processField(Field field) throws UnsupportedEncodingException {
        byte[] fieldData = getBytesForField(field);
        FieldNameEnum fieldName = field.getFieldName();
        switch (fieldName) {
            case SURNAME:
                String surname = decodeByteData(fieldData);
                String formattedSurname = surname.substring(0, 1).toUpperCase()
                        + surname.substring(1, surname.length()).toLowerCase();
                formData.setSurname(formattedSurname.trim());
                break;
            case INITIALS:
                String initials = decodeByteData(fieldData);
                String formattedInitials = initials.charAt(0) + StringUtil.DOT + StringUtil.SPACE
                        + initials.charAt(1) + StringUtil.DOT;
                formData.setInitials(formattedInitials);
                break;
            case VARIANT:
                String variant = decodeByteData(fieldData).trim();
                formData.setVariant(variant);
                break;
            case CLASS_LETTER:
                formData.setClassLetter(decodeByteData(fieldData));
                break;
            case FIRST_SUBJECT:
                formData.addSubjectData(createSubjectData(fieldData, fieldName, SubjectEnum.MATH));
                break;
            case SECOND_SUBJECT:
                formData.addSubjectData(createSubjectData(fieldData, fieldName, SubjectEnum.KAZAKH));
                break;
            case THIRD_SUBJECT:
                formData.addSubjectData(createSubjectData(fieldData, fieldName, SubjectEnum.RUSSIAN));
                break;
            case FOURTH_SUBJECT:
                formData.addSubjectData(createSubjectData(fieldData, fieldName, SubjectEnum.KAZAKH_HISTORY));
                break;
            case FIFTH_SUBJECT:
                SubjectEnum subjectEnum = getSubjectForField(fieldName);
                formData.addSubjectData(createSubjectData(fieldData, fieldName, subjectEnum));
                break;
        }
    }

    private byte[] getBytesForField(Field field) {
        int startPosition = field.getStartPosition();
        int endPosition = startPosition + field.getLength();
        return Arrays.copyOfRange(data, startPosition, endPosition);
    }

    private SubjectData createSubjectData(byte[] data, FieldNameEnum fieldName, SubjectEnum subject)
            throws UnsupportedEncodingException {
        SubjectData subjectData = new SubjectData();
        subjectData.setSubjectEnum(subject);
        subjectData.setFormData(formData);
        subjectData.setFieldName(fieldName);
        fillAnswersForSubject(data, subjectData);
        return subjectData;
    }

    private void fillAnswersForSubject(byte[] data, SubjectData subjectData) throws UnsupportedEncodingException {
        int number = 1;
        for (byte b : data) {
            AnswerData answerData = new AnswerData();
            String answer = decodeByte(b);
            answerData.setValue(answer);
            answerData.setQuestionNumber(number++);
            subjectData.addAnswer(answerData);
        }
    }

    private SubjectEnum getSubjectForField(FieldNameEnum fieldDame) {
        FieldNameEnum subjectNameFieldEnum = SUBJECT_FIELD_MAP.get(fieldDame);
        Field subjectNameField = form.getFields().get(subjectNameFieldEnum);
        byte[] fieldData = getBytesForField(subjectNameField);
        BigInteger integer = new BigInteger(fieldData);
        return SUBJECT_VALUE_MAP.get(integer.intValue());
    }

    private String decodeByteData(byte[] data) throws UnsupportedEncodingException {
        StringBuilder builder = new StringBuilder();
        for (byte b : data) {
            builder.append(decodeByte(b));
        }
        return builder.toString();
    }

    private String decodeByte(byte b) throws UnsupportedEncodingException {
        String value = KAZAKH_LETTER.get(b);
        if (value == null) {
            value = new String(new byte[]{b}, DEFAULT_CHARSET);
        }
        return value;
    }
}
